<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <script>
      //改变this指向的三种方法
      //this不要关注this 的定义  需要关注this 的调用
      //一.call : function.call(this,参数1,参数2..)
      //"use strict"
      function fn(a, b) {
        console.log("fn里的this是", this, a, b);
      }
      //1.直接调用 指向window  2.严格模式下调用指向undefined  3.实例化调用的是指向实例化对象 4.对象.fn调用会指向对象
      //fn();
      //   var res = new fn();
      var obj = {
        fn: fn,
        name: "张三",
      };
      //   obj.fn();
      var myfn = obj.fn;
      myfn();
      //直接调用
      fn(1, 2);
      //调用的同时 改变fn函数里的this 指向
      var obj = { name: 123 };
      fn.call(obj, 1, 2);
      //注意: call一般会改对象为函数里的this
      //如果call的是undefined  和 null  那么函数内的this会指向window
      //如果call是简单的数据类型,那么函数里的this会指向,简单数据类型的对象形式
      fn.call({ name: "hello" }, 1, 2);
      fn.call(null, 1, 2);
      fn.call(123, 1, 2);

      //二.apply方法  function.apply(this,[参数1,参数2,参数3])
      function fn(a, b) {
        console.log(this, a, b);
      }

      fn.call({ name: "hello" }, 1, 2);
      fn.apply({ name: "hello" }, [1, 2]);

      //apply方法 更方便的接受数组类型的不定参
      function fn2() {
        //需要接受fn1的所有参数  fn1的参数 不恒定
        console.log("fn2", this, arguments); //obj的this
      }

      function fn1() {
        var obj = {
          name: "hello",
        };
        console.log(arguments);
      }

      fn2.call(obj);
      fn2.apply(obj.arguments);

      fn1(1, 2, 3, 4);

      // 三.bind  function.bind(this)(参数1,参数2,参数3)
      //需要执行2次  调用两次小括号

      function fn(a, b) {
        console.log("fn的this是", this, a, b);
      }

      var obj = {
        name: 123,
      };
      fn.bind(obj)(1, 2); //延迟执行

      function myfn() {
        console.log("打印了", this);
      }

      document.onclick = myfn;
      document.onclick = myfn.call({ name: 123 });
      document.onclick = function () {
        myfn.call({ name: 123 });

        // document.onclick = myfn.bind({name:123});
      };

      /* 
      总结:
      如果传入的是null  undefined 那么函数会指向window
      如果传入的是简单数据类型 那么函数会把简单数据类型包装成对象
      call: 参数需要一个一个传入
      apply: 参数需要一个数组
      bind: 需要执行两次
      */
    </script>
  </body>
</html>
